package com.bitter.redisson.lock;

import cn.hutool.core.date.SystemClock;
import org.apache.logging.log4j.util.Supplier;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.concurrent.TimeUnit;

/**
 * @author thomas.he
 * @date 2022/6/9
 **/
public class MyRedissonDistributedLocker implements DistributedLocker {


    final  org.slf4j.Logger logger  = LoggerFactory.getLogger(MyRedissonDistributedLocker.class);
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public RLock lock(String lockKey) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    @Override
    public RLock lock(String lockKey, long timeout) {
        RLock rLock = this.redissonClient.getLock(lockKey);
        rLock.lock(timeout,TimeUnit.SECONDS);
        return rLock;
    }

    @Override
    public RLock lock(String lockKey, TimeUnit unit, long timeout) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    @Override
    public boolean tryLock(String lockKey, TimeUnit unit, long leaseTime) {
        RLock lock = this.redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(0L, leaseTime, unit);
        } catch (InterruptedException var7) {
            return false;
        }
    }

    @Override
    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }

    @Override
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
       if(lock.isLocked()) {
           lock.unlock();
       }
    }

    @Override
    public void unlock(RLock lock) {
        try {
            if (lock.isLocked()) {
                lock.unlock();
            }
        } catch (IllegalMonitorStateException var3) {}
    }

    @Override
    public <T> T tryLockAndRun(String lockKey, TimeUnit unit, long waitTime, long leaseTime, Supplier<T> supplier, String scene) {
            final long start = SystemClock.now();
            // 获取分布式锁，最长等待时间:10秒,20秒后自动释放。注意锁与事务的顺序：获取分布式锁 -> 开启事务 -> 执行业务 -> 提交事务 -> 释放分布式锁！！！
            final boolean tryLock = this.tryLock(lockKey, unit, waitTime, leaseTime);
            final long end = SystemClock.now();
            if (!tryLock) {
                logger.error("[{}]获取分布式锁失败，lockKey = {}，耗时{}ms", scene, lockKey, end - start);
            }

            // 注意：一定是获取锁成功后，才进行try{}finally{释放锁}
            try {
                logger.info("[{}]获取分布式锁成功，lockKey = {}，耗时{}ms", scene, lockKey, end - start);
                return supplier.get();
            } finally {
                this.unlock(lockKey);
            }
    }
}
